#ifdef WIN32

#include "socketWin.h"
#include "log.h"

void Startup()
{
	WSAData    wsaData;

	if(WSAStartup(MAKEWORD(2,2), &wsaData) == NO_ERROR)
	{
		return;
	}
	
	ELOG("SocketWin::StartUp() failed, ERR = %d\n", GetLastError());
}

void Cleanup()
{
	WSACleanup();
}

SocketWin::SocketWin(SocketType socketType)
: Socket(socketType)
{
}

SocketWin::~SocketWin()
{
	CloseSocket();
}

bool SocketWin::CloseSocket()
{
	if(m_socket >= 0)
	{
		closesocket(m_socket); 
		m_socket = -1; 
	}	

	return true;
}

int SocketWin::GetLastError()
{
	return WSAGetLastError();
}

bool SocketWin::CreateSocket(int socketId)
{
	if(socketId != -1)
	{
		m_socket = socketId;
		return true;
	}

	if(SOCKET_TYPE_TCP == m_socketType)
	{
		if((m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != INVALID_SOCKET)
		{
			return true;
		}
	}
	else if(SOCKET_TYPE_UDP == m_socketType)
	{
		if((m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != INVALID_SOCKET)
		{
			return true;
		}
	}

	ELOG("SocketWin::CreateSocket failed: %d, m_socketType: %d\n", GetLastError(), m_socketType);

	return false;
}

bool SocketWin::SetNonBlocking()
{
	unsigned long x = 1;

	if(ioctlsocket(m_socket, FIONBIO, (unsigned long*)&x) != SOCKET_ERROR)
	{
		m_bIsBlocking = false;

		return true;
	}

	ELOG("SocketWin::SetNonBlocking failed: %d\n", GetLastError());

	return false;
}

bool SocketWin::Bind(uint16 port, char* ip)
{
	sockaddr_in		addr_in;

	addr_in.sin_family = AF_INET;
	addr_in.sin_port = htons(port);
	if(ip == NULL)
		addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
	else
		addr_in.sin_addr.s_addr = inet_addr(ip);

	if(bind(m_socket, (sockaddr*)&addr_in, sizeof(addr_in)) != SOCKET_ERROR)
	{
		sockaddr_in		me;
		int				len = 0;

		memset(&me, 0, sizeof(me));
		len = sizeof(me);
		if(getsockname(m_socket, (sockaddr*)&me, &len) != SOCKET_ERROR)
		{
			m_bindPort = ntohs(me.sin_port);
			
			LOGOUT("SocketWin::Bind--> port: %d\n", m_bindPort);
			
			return true;
		}
		
		m_bindPort = port;
		
		ELOG("SocketWin::Bind failed, Get Port Failed, m_bindPort: %d\n", m_bindPort);

		return true;
	}

	ELOG("SocketWin::Bind failed, error: %d, port: %d\n", GetLastError(), port);

	return false;
}

bool SocketWin::Listen(int backLop)
{
	if(backLop <= 0)
		backLop = SOMAXCONN;

	if(listen(m_socket, backLop) != SOCKET_ERROR)
	{
		return true;
	}

	ELOG("SocketWin::Listen failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::Accept(int& socket, char* &ip, uint16& port)
{
	sockaddr_in  addr_in;
	int			 addr_in_len = sizeof(addr_in);

	addr_in.sin_family = AF_INET;

	if((socket = accept(m_socket, (sockaddr*)&addr_in, &addr_in_len)) != INVALID_SOCKET)
	{
		ip = StringNew(inet_ntoa(addr_in.sin_addr));
		port = ntohs(addr_in.sin_port);

		return true;
	}

	ELOG("SocketWin::Accept failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::Connect(char* ip, uint16 port)
{
	sockaddr_in			addr_in;

	addr_in.sin_family = AF_INET;
	addr_in.sin_addr.s_addr = inet_addr(ip);	
	addr_in.sin_port = htons(port);

	if(connect(m_socket, (sockaddr*)&addr_in, sizeof(addr_in)) != SOCKET_ERROR)
	{
		return true;
	}

	//ELOG("SocketWin::Connect failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::Send(const char* buffer, int& size)
{
	int lenBuffer = (size > ONLINE_MAX_PACKET_SIZE) ? ONLINE_MAX_PACKET_SIZE : size;

	if((size = send(m_socket, buffer, lenBuffer, 0)) != SOCKET_ERROR)
	{
		return true;
	}

	//ELOG("SocketWin::Send failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::SendTo(const char* buffer, int& size, char* ip, uint16 port)
{
	int lenBuffer = (size > ONLINE_MAX_PACKET_SIZE) ? ONLINE_MAX_PACKET_SIZE : size;

	sockaddr_in		addr_in;
	addr_in.sin_family = AF_INET;
	addr_in.sin_addr.s_addr = inet_addr(ip);
	addr_in.sin_port = htons(port);

	if((size = sendto(m_socket, buffer, lenBuffer, 0, (sockaddr*)&addr_in, sizeof(addr_in))) != SOCKET_ERROR)
	{
		return true;
	}

	//ELOG("SocketWin::SendTo failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::Recv(char* &buffer, int& size)
{
	int lenBuffer = (size > ONLINE_MAX_PACKET_SIZE) ? ONLINE_MAX_PACKET_SIZE : size;

	if((size = recv(m_socket, buffer, lenBuffer, 0)) != SOCKET_ERROR)
	{
		return true;
	}

	//ELOG("SocketWin::Recv failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::RecvFrom(char* &buffer, int& size, char* &ip, uint16& port)
{
	int lenBuffer = (size > ONLINE_MAX_PACKET_SIZE) ? ONLINE_MAX_PACKET_SIZE : size;

	sockaddr_in	addr_in;
	int			addr_in_len = sizeof(addr_in);

	addr_in.sin_family = AF_INET;

	if((size = recvfrom(m_socket, buffer, lenBuffer, 0, (sockaddr*)&addr_in, &addr_in_len)) != SOCKET_ERROR)
	{
		ip = StringNew(inet_ntoa(addr_in.sin_addr));
		port = ntohs(addr_in.sin_port);

		return true;
	}

	//ELOG("SocketWin::RecvFrom failed, error: %d\n", GetLastError());

	return false;
}

bool SocketWin::Select(SocketSelectFlag selectFlag)
{
	timeval tval = {0, 0};
	 
	FD_ZERO(&m_fdSet);
	FD_SET(m_socket, &m_fdSet);

	int value = -1;
	if(SOCKET_SELECT_READ == selectFlag)
	{
		value = select(m_socket + 1, &m_fdSet, NULL, NULL, &tval);
	}
	else if (SOCKET_SELECT_WRITE == selectFlag)
	{
		value = select(m_socket + 1, NULL, &m_fdSet, NULL, &tval);
	}
	else
	{
	}

	if (FD_ISSET(m_socket, &m_fdSet))
	{
		return true;
	}
	else
	{
		return false;
	}
}

#endif